﻿// -------------------------------------------------------------------------
//    @FileName         :    NFItemUseFactory.cpp
//    @Author           :    Gao.Yi
//    @Date             :    2025-10-24
//    @Email			:    445267987@qq.com
//    @Module           :    NFItemUseFactory
//    @Desc             :
//
// -------------------------------------------------------------------------

// --- 文件总结 ---------------------------------------------------------------
// 本文件实现 NFItemUseFactory 类的功能：
// 
// 【构造/析构】
// - NFItemUseFactory：构造函数，调用 RegisterAll 注册所有物品使用处理器
// - ~NFItemUseFactory：析构函数
// 
// 【注册和获取】
// - RegisterAll：注册所有物品类型的使用处理器
//   * EN_ITEM_TYPE_PROP：道具物品处理器
//   * EN_ITEM_TYPE_BOX：宝箱物品处理器
//   * EN_ITEM_TYPE_RANDOM_QUALITY：品质物品处理器
//   * EN_ITEM_TYPE_BUFF：Buff物品处理器
// - GetHandler：根据物品类型获取对应的使用处理器
// 
// 【物品使用处理器】
// - PropItemUseHandler：道具物品使用处理器（待实现）
// - BoxItemUseHandler：宝箱物品使用处理器
//   * 检查物品类型和参数
//   * 检查临时存储
//   * 根据掉落ID计算掉落物品
//   * 删除使用的宝箱物品和消耗物品
//   * 添加掉落物品到背包
//   * 提交变更并发送奖励通知
// - QualityItemUseHandler：品质物品使用处理器（待实现）
// - AddBuffItemUseHandler：Buff物品使用处理器（待实现）
// ---------------------------------------------------------------------------

#include "NFItemUseFactory.h"

#include "NFLogicCommon/BagPage/NFBagPageOp.h"
#include "NFBagPageOpMgr.h"
#include "NFDropUtil.h"
#include "NFPlayer.h"
#include "NFServicePackage.h"
#include "NFServiceSkill.h"
#include "NFSkillUtil.h"
#include "NFSysMsgUtil.h"
#include "DescStore/BroadCastDesc.h"

NFItemUseFactory::NFItemUseFactory()
{
    RegisterAll();
}

NFItemUseFactory::~NFItemUseFactory()
{
}

int NFItemUseFactory::RegisterAll()
{
    for (int i = 0; i < proto_ff::enItemType_ARRAYSIZE; i++)
    {
        m_apItemUseHandle[i] = nullptr;
    }

    m_apItemUseHandle[proto_ff::EN_ITEM_TYPE_PROP] = &NFItemUseFactory::PropItemUseHandler;
    m_apItemUseHandle[proto_ff::EN_ITEM_TYPE_BOX] = &NFItemUseFactory::BoxItemUseHandler;
    m_apItemUseHandle[proto_ff::EN_ITEM_TYPE_RANDOM_QUALITY] = &NFItemUseFactory::QualityItemUseHandler;
    m_apItemUseHandle[proto_ff::EN_ITEM_TYPE_BUFF] = &NFItemUseFactory::AddBuffItemUseHandler;
    return 0;
}

NFUseItemHandler NFItemUseFactory::GetHandler(int itemType)
{
    if (proto_ff::enItemType_IsValid(itemType))
    {
        return m_apItemUseHandle[itemType];
    }

    return nullptr;
}

int NFItemUseFactory::PropItemUseHandler(NFPlayer* pPlayer, const proto_ff::Proto_CSUseItemReq& oUseItemReq, const E_Item* pstItemDesc, proto_ff::Proto_CSUseItemRsp* pResult, bool bNeedCheckCD)
{
    return 0;
}

int NFItemUseFactory::BoxItemUseHandler(NFPlayer* pPlayer, const proto_ff::Proto_CSUseItemReq& oUseItemReq, const E_Item* pstItemDesc, proto_ff::Proto_CSUseItemRsp* pResult, bool bNeedCheckCD)
{
    int iRetCode = 0;
    CHECK_NULL(0, pPlayer);
    CHECK_NULL(0, pstItemDesc);

    CHECK_EXPR(pstItemDesc->item_type != proto_ff::EN_ITEM_TYPE_BOX || pstItemDesc->item_sub_type != proto_ff::EN_SELECTED_BOX, proto_ff::ERR_CODE_INVALID_REQ_PARAM, "can not use:{}", pstItemDesc->id);

    int iGridIndex = oUseItemReq.grid_index();
    int iNum = oUseItemReq.has_num() ? oUseItemReq.num() : 1;
    int iPage = oUseItemReq.grid_page();
    if (iPage == 0)
    {
        iPage = pstItemDesc->bag_page_type;
        CHECK_EXPR(iPage > 0, proto_ff::ERR_CODE_INVALID_REQ_PARAM, "item can not be use by grid itemId:{} iNum:{}", pstItemDesc->id, iNum);
    }

    if (iGridIndex < 0)
    {
        CHECK_EXPR(iNum == 1, proto_ff::ERR_CODE_INVALID_REQ_PARAM, "no grid:{}", oUseItemReq.DebugString());
    }

    if (NFServicePackage::IsTempStorageHasItem(pPlayer))
    {
        return proto_ff::ERR_CODE_TEMP_STORAGE_HAS_ITEM;
    }

    std::vector<WillAddItemDataWithNum> vecAddItem;
    for (int i = 0; i < iNum; i++)
    {
        iRetCode = NFDropUtil::Drop(pstItemDesc->linked_drop_id, pPlayer->GetLevel(), NFServiceSkill::GetTransferId(pPlayer), vecAddItem);
        CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "drop error, dropId:{}", pstItemDesc->linked_drop_id);
    }

    NFBagPageOpMgr opMgr(pPlayer, proto_ff::EN_ICR_USE_ITEM, true);
    auto pBagOp = opMgr.GetBagPageOpByBagType(iPage);
    CHECK_NULL_WF(pPlayer->GetRoleID(), pBagOp, "page index error:{}", iPage);
    if (iGridIndex < 0)
    {
        iRetCode = opMgr.DelItems(pstItemDesc->id, (int)iNum);
        CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "del item error, iGridIndex:{} iNum:{}", iGridIndex, iNum);
    }
    else
    {
        iRetCode = pBagOp->DelItemByGridWithNum(iGridIndex, iNum);
        CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "del item error, iGridIndex:{} iNum:{}", iGridIndex, iNum);
    }

    if (pstItemDesc->box_consume_id > 0 && pstItemDesc->box_consume_num > 0)
    {
        iRetCode = opMgr.DelItems(pstItemDesc->box_consume_id, pstItemDesc->box_consume_num * iNum);
        CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "del item error, iGridIndex:{} iNum:{}", iGridIndex, iNum);
    }

    iRetCode = opMgr.AddToBag(vecAddItem);
    CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "add item error");

    iRetCode = opMgr.Commit(true);
    CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "commit error");

    opMgr.SendRewardNtf(true, proto_ff::EN_REWARD_NOTIFY_TYPE_USE_ITEM, pstItemDesc->id);

    // BroadCast :  hot fix code
    if (pstItemDesc->broadcast_id == 0 || pstItemDesc->broadcast_id == 3833)
    {
        return 0;
    }

    auto pBroadCaseDesc = BroadCastDesc::Instance()->GetDesc(pstItemDesc->broadcast_id);
    if (!pBroadCaseDesc)
    {
        LOG_ERR(pPlayer->GetRoleID(), -1, "broadcast_id error:{}", pstItemDesc->broadcast_id)
        return 0;
    }

    std::vector<proto_ff::SysMsgEscapePara> paraList;
    opMgr.FillPackageInfoForAdd(pResult->mutable_items());
    NFSysMsgUtil::Broadcast(pstItemDesc->broadcast_id, paraList);
    return 0;
}

int NFItemUseFactory::QualityItemUseHandler(NFPlayer* pPlayer, const proto_ff::Proto_CSUseItemReq& oUseItemReq, const E_Item* pstItemDesc, proto_ff::Proto_CSUseItemRsp* pResult, bool bNeedCheckCD)
{
    return 0;
}

int NFItemUseFactory::AddBuffItemUseHandler(NFPlayer* pPlayer, const proto_ff::Proto_CSUseItemReq& oUseItemReq, const E_Item* pstItemDesc, proto_ff::Proto_CSUseItemRsp* pResult, bool bNeedCheckCD)
{
    return 0;
}
